package com.uex.dev.manage.admin.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.ObjectUtils;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.github.yulichang.wrapper.MPJLambdaWrapper;
import com.google.common.base.Preconditions;
import com.uex.dev.manage.admin.config.MiniserveConfig;
import com.uex.dev.manage.admin.dao.DeviceDao;
import com.uex.dev.manage.admin.dao.ProjectDao;
import com.uex.dev.manage.admin.enums.DeviceTypeEnum;
import com.uex.dev.manage.admin.po.*;
import com.uex.dev.manage.admin.service.*;
import com.uex.dev.manage.admin.utils.LogUtil;
import com.uex.dev.manage.admin.vo.device.*;
import com.uex.dev.manage.common.base.PageResult;
import io.micrometer.common.util.StringUtils;
import jakarta.annotation.Resource;
import jakarta.servlet.http.HttpServletResponse;
import org.apache.commons.io.FileUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;

import java.io.File;
import java.io.IOException;
import java.io.OutputStream;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;

/**
 * <p>
 * 服务实现类
 * </p>
 *
 * @author wangchao
 * @since 2024-02-22
 */
@Service
public class DeviceServiceImpl extends ServiceImpl<DeviceDao, DevicePO> implements IDeviceService {

    @Resource
    private IDeviceImgService deviceImgService;

    @Resource
    private IDeviceRobotService deviceRobotService;

    @Resource
    private IDeviceUhubService deviceUhubService;

    @Resource
    private IModelRobotService modelRobotService;

    @Resource
    private IModelUhubService modelUhubService;

    @Resource
    private IDeviceModelService deviceModelService;

    @Resource
    private ProjectDao projectDao;

    @Resource
    private MiniserveConfig miniserveConfig;

    @Override
    public Boolean replaceToken(ReplaceTokenReq req) {
        Preconditions.checkArgument(StringUtils.isNotBlank(req.getDeviceToken()), "唯一标识不能为空");
        Preconditions.checkArgument(StringUtils.isNotBlank(req.getReplaceToken()), "替换标识不能为空");
        DevicePO device = this.getDeviceByDevToken(req.getDeviceToken());
        Preconditions.checkArgument(ObjectUtils.isNotNull(device), "唯一标识不存在");
        // 历史唯一标识为空，则初始化
        if (ObjectUtils.isEmpty(device.getDeviceHisToken())) {
            device.setDeviceHisToken(new ArrayList<>());
        }
        device.getDeviceHisToken().add(device.getDeviceToken());
        device.setDeviceToken(req.getReplaceToken());
        LogUtil.log(device.getId(), "替换设别唯一标识");
        return this.updateById(device);
    }

    @Override
    public PageResult<DevicePageResp> pageDevice(DevicePageReq devicePageReq) {
        Page<DevicePageResp> page = new Page<>(devicePageReq.getPage(), devicePageReq.getRecord());
        Page<DevicePageResp> result = this.selectJoinListPage(page,DevicePageResp.class, new MPJLambdaWrapper<DevicePO>()
                        .select("t.*,prj_name")
                        .leftJoin(ProjectPO.class,ProjectPO::getPrjId,DevicePO::getDevicePrjid)
                .eq(ObjectUtils.isNotNull(devicePageReq.getDeviceType()), DevicePO::getDeviceType, devicePageReq.getDeviceType())
                .eq(ObjectUtils.isNotNull(devicePageReq.getDevicePrjid()), DevicePO::getDevicePrjid, devicePageReq.getDevicePrjid())
                .eq(StringUtils.isNotBlank(devicePageReq.getDeviceModel()), DevicePO::getDeviceModel, devicePageReq.getDeviceModel())
                .like(StringUtils.isNotBlank(devicePageReq.getDeviceToken()), DevicePO::getDeviceToken, devicePageReq.getDeviceToken())
                .orderByDesc(DevicePO::getDeviceCreateTime)
        );
        LogUtil.log(0, "获取设备列表");
        return PageResult.build((result));
    }

    @Override
    public DeviceInfoResp getInfoDevice(String deviceToken) {
        DevicePO device = this.getDeviceByDevToken(deviceToken);
        Preconditions.checkArgument(ObjectUtils.isNotNull(device), "设备唯一标识不存在");
        LambdaQueryWrapper<DeviceImgPO> wrapperByType = Wrappers.<DeviceImgPO>lambdaQuery()
                .eq(DeviceImgPO::getDeviceType, device.getDeviceType());
        List<DeviceImgPO> list = deviceImgService.list(wrapperByType);
        ArrayList<String> infoList = new ArrayList<>();
        list.forEach(x -> infoList.add(x.getImgUrl()));
        DeviceInfoResp deviceInfoResp = new DeviceInfoResp();
        BeanUtils.copyProperties(device, deviceInfoResp);
        deviceInfoResp.setDeviceImgs(infoList);
        LogUtil.log(device.getId(), "获取设备信息");
        return deviceInfoResp;
    }

    @Override
    public void updateInfoDevice(DevicePO deviceUpdateInfoReq) {
        DevicePO device = new DevicePO();
        if (deviceUpdateInfoReq.getId() != null && deviceUpdateInfoReq.getId() != 0) {
            device = this.getById(deviceUpdateInfoReq.getId());
            Preconditions.checkArgument(ObjectUtils.isNotNull(device), "设备ID不存在");
            if (!device.getDeviceToken().equals(deviceUpdateInfoReq.getDeviceToken())) {
                device.getDeviceHisToken().add(deviceUpdateInfoReq.getDeviceToken());
            }
            BeanUtils.copyProperties(deviceUpdateInfoReq, device);
            this.updateById(device);
            LogUtil.log(device.getId(), "更新设备信息");
        }else{
            Preconditions.checkArgument(StringUtils.isNotBlank(deviceUpdateInfoReq.getDeviceToken()), "设备唯一标识不能为空");
            Preconditions.checkArgument(Objects.isNull(this.getDeviceByDevToken(deviceUpdateInfoReq.getDeviceToken())), "设备唯一标识已存在");
            Preconditions.checkArgument(Objects.nonNull(deviceUpdateInfoReq.getDeviceType()), "设备类型不能为空");
            Preconditions.checkArgument(Objects.nonNull(deviceUpdateInfoReq.getDeviceModelid()), "设备型号Id不能为空");
            DeviceModelPO deviceModel = deviceModelService.getById(deviceUpdateInfoReq.getDeviceModelid());
            Preconditions.checkArgument(ObjectUtils.isNotNull(deviceModel), "设备型号不存在");
            BeanUtils.copyProperties(deviceUpdateInfoReq, device);
            device.setDeviceModelid(deviceModel.getId());
            device.setDeviceModel(deviceModel.getDeviceModel());
            device.setDeviceCreateTime(LocalDateTime.now());
            this.save(device);
            if (deviceUpdateInfoReq.getDeviceType() == DeviceTypeEnum.UHUB) {
                ModelUhubPO modelUhub = modelUhubService.getById(deviceUpdateInfoReq.getDeviceModelid());
                DeviceUhubPO deviceUhub = new DeviceUhubPO();
                BeanUtils.copyProperties(modelUhub, deviceUhub);
                deviceUhub.setDeviceId(device.getId());
                deviceUhubService.save(deviceUhub);
            } else {
                ModelRobotPO modelRobot = modelRobotService.getById(deviceUpdateInfoReq.getDeviceModelid());
                DeviceRobotPO deviceRobot = new DeviceRobotPO();
                BeanUtils.copyProperties(modelRobot, deviceRobot);
                deviceRobot.setDeviceId(device.getId());
                deviceRobotService.save(deviceRobot);
            }
            miniserveMkdirDirectory(device.getDeviceType().toString(), device.getDeviceModel());
            LogUtil.log(device.getId(), "添加设备信息");
        }
    }

    @Override
    public List<DevicePageResp> getDeviceList(Integer prjId) {
        Preconditions.checkArgument(ObjectUtils.isNotNull(prjId), "项目Id不能为空");
        ProjectPO project = projectDao.selectById(prjId);
        Preconditions.checkArgument(ObjectUtils.isNotNull(project), "项目Id不存在");
        LambdaQueryWrapper<DevicePO> wrapperByPrjid = Wrappers.<DevicePO>lambdaQuery()
                .eq(DevicePO::getDevicePrjid, prjId)
                .orderByDesc(DevicePO::getId);
        List<DevicePO> deviceList = this.list(wrapperByPrjid);
        ArrayList<DevicePageResp> resultList = new ArrayList<>();
        deviceList.forEach(device -> {
            DevicePageResp devicePageResp = DevicePageResp.fromPO(device);
            resultList.add(devicePageResp);
        });
        LogUtil.log(0, "获取项目对应设备列表");
        return resultList;
    }

//    @Override
//    public Boolean addRobot(AddRobotReq addRobotReq) {
//        Preconditions.checkArgument(ObjectUtils.isNotNull(addRobotReq.getDeviceToken()), "设备唯一标识不能为空");
//        DevicePO device = this.getDeviceByDevToken(addRobotReq.getDeviceToken());
//        Preconditions.checkArgument(ObjectUtils.isNull(device), "设备已存在");
//        // 添加设备
//        this.save(addRobotReq.convertDevicePO());
//        device = this.getDeviceByDevToken(addRobotReq.getDeviceToken());
//        DeviceRobotPO deviceRobot = addRobotReq.convertPO();
//        deviceRobot.setDeviceId(device.getId());
//        LogUtil.log(deviceRobot.getDeviceId(), "上传收单机信息");
//        return deviceRobotService.save(deviceRobot);
//    }

//    @Override
//    public Boolean addScanner(AddScannerReq addScannerReq) {
//        Preconditions.checkArgument(ObjectUtils.isNotNull(addScannerReq.getDeviceToken()), "设备唯一标识不能为空");
//        DevicePO device = this.getDeviceByDevToken(addScannerReq.getDeviceToken());
//        Preconditions.checkArgument(ObjectUtils.isNull(device), "设备已存在");
//        this.save(addScannerReq.convertDevicePO());
//        DeviceRobotPO deviceRobot = addScannerReq.convertPO();
//        deviceRobot.setDeviceId(device.getId());
//        LogUtil.log(deviceRobot.getDeviceId(), "上传扫描仪信息");
//        return deviceRobotService.save(deviceRobot);
//    }

//    @Override
//    public Boolean addUhub(AddUhubReq addUhubReq) {
//        Preconditions.checkArgument(StringUtils.isNotBlank(addUhubReq.getDeviceToken()), "设备唯一标识不能为空");
//        Preconditions.checkArgument(StringUtils.isNotBlank(addUhubReq.getDeviceModel()), "设备型号不能为空");
//        Preconditions.checkArgument(ObjectUtils.isNotNull(addUhubReq.getDevicePortNum()), "端口数量不能为空");
//        Preconditions.checkArgument(ObjectUtils.isNotNull(addUhubReq.getDeviceUkeyNum()), "按键精灵数量不能为空");
//        DevicePO device = this.getDeviceByDevToken(addUhubReq.getDeviceToken());
//        Preconditions.checkArgument(ObjectUtils.isNull(device), "设备已存在");
//        this.save(addUhubReq.convertDevicePO());
//        DeviceUhubPO deviceUhub = addUhubReq.convertPO();
//        deviceUhub.setDeviceId(device.getId());
//        LogUtil.log(deviceUhub.getDeviceId(), "上传云盾基本信息");
//        return deviceUhubService.save(deviceUhub);
//    }

    @Override
    public void exportDevice(String deviceToken, HttpServletResponse response) {
        Preconditions.checkArgument(StringUtils.isNotBlank(deviceToken), "设备唯一标识不能为空");
        DevicePO device = this.getDeviceByDevToken(deviceToken);
        Preconditions.checkArgument(device != null, "设备唯一标识不存在");
        DeviceCapacity deviceCapacity = new DeviceCapacity();
        DeviceTypeEnum deviceType = device.getDeviceType();
        deviceCapacity.setDeviceModel(device.getDeviceModel());
        deviceCapacity.setDeviceType(deviceType);
        if (deviceType == DeviceTypeEnum.UHUB) {
            UhubInfo uhub = deviceUhubService.getUhubInfo(device.getId());
            deviceCapacity.setDeviceCapacity(uhub);
        } else {
            RobotInfo robot = deviceRobotService.getRobotInfo(device.getId());
            deviceCapacity.setDeviceCapacity(robot);
        }
        ObjectMapper objectMapper = new ObjectMapper();
        String fileName = deviceType + "-" + device.getId().toString() + ".json";
        response.setContentType("application/json");
        response.setHeader("Content-Disposition", "attachment; filename=\"" + fileName + "\"");
        try (OutputStream outputStream = response.getOutputStream()) {
            objectMapper.writeValue(outputStream, deviceCapacity);
            outputStream.flush();
        } catch (IOException e) {
            log.error("导出文件失败", e);
            throw new RuntimeException(e);
        }
    }


    private void miniserveMkdirDirectory(String deviceType, String devModel) {
        String imgDir = miniserveConfig.getPath() + miniserveConfig.getImg().replace("{devType}", deviceType).replace("{devModel}", devModel);
        try {
            FileUtils.forceMkdir(new File(imgDir));
        } catch (Exception e) {
            log.error("[DeviceService] mkdir error", e);
        }
    }
}
